package require tdom

set root ""

#从配置文件中载入配置信息
proc initXml {configFileName} {
	global root
	if {[catch {set configFile [open $configFileName r]} errMsg]} {
		puts "Failed to open the file for reading: $errMsg"
		return
	} else {
		set content [read $configFile]
		if {[catch {set doc [dom parse $content]} errMsg]} {
			puts "Invalid xml file"
			exit 1
		}
		set root [$doc documentElement]
	}
}

#获取一共需要连接的设备数
proc getEquipNumber {} {
	global root
	rootIsSet
	set equipments [$root selectNodes /config/equipments]
	set count 0
	foreach child [$equipments childNodes] {
		incr count
	}
	return $count
}

#获取设备的连接信息
#index：传入想要获取的设备连接信息的编号
#返回一个字典类型，包括ip、name、pwd、id
proc getConnectorInfo {index} {
	global root
	rootIsSet
	set ip [parseConnectorInfo ip $index]
	set name [parseConnectorInfo name $index]
	set pwd [parseConnectorInfo pwd $index]
	set id [parseConnectorInfo id $index]
	dict append info ip $ip
	dict append info name $name
	dict append info pwd $pwd
	dict append info id $id
	return $info
}

#解析连接信息的公共方法
proc parseConnectorInfo {infoName id} {
	global root
	set equip [$root selectNodes /config/equipments/equipment]
	set equip [lindex $equip $id]
	set info [$equip selectNodes connector-info/$infoName/text()]
	if {[catch {set info [$info data]} errMsg]} {
		puts "Equipment $id lacks some connect configuration information"
		exit 1
	}
	return $info
}

#获取设备配置信息
#这个方法返回的是设备的端口信息的配置信息，不包括协议的配置信息
#返回一个字典类型，该字典类型中包括两个key，分别是设备的id(id)和端口配置信息的一个链表(ports-conf)，
#端口配置信息的链表中每一个元素是一个端口的配置信息组成的字典，该字典的key:
#port-number 端口号
#port-ip 端口的ip
#port-mask 端口的掩码
#clock-rate 端口的时钟
proc getConfInfo {index} {
	global root
	rootIsSet
	set equipments [$root selectNodes /config/equipments/equipment]
	set equipment [lindex $equipments $index]
	set id [$equipment selectNodes config-info/id/text()]
	if {[catch {set id [$id data]} errMsg]} {
		puts "Equipment $index lacks config-info/id tag"
		exit 1
	}
	dict append confInfo id $id
	set ports {}
	set portsConf [$equipment selectNodes config-info/ports-conf]
	foreach port [$portsConf childNodes] {
		set portInfo ""
		set judge [catch {
			set portNumber [parseTextInfo $port port-number]
			set portIP [parseTextInfo $port port-ip]
			set portMask [parseTextInfo $port port-mask]
		} errMsg]
		if { $judge } {
			puts "Equipment $index lacks some port configuration information"
			exit 1
		}
		set clockRate [$port selectNodes clock-rate/text()]
		if {[catch {set clockRate [$clockRate data]} errMsg]} {
			set clockRate ""
		}
	
		dict append portInfo port-number $portNumber
		dict append portInfo port-ip $portIP
		dict append portInfo port-mask $portMask
		dict append portInfo clock-rate $clockRate
		lappend ports $portInfo
		set portInfo [dict remove $portInfo port-number port-ip port-mask clock-rate]
	}
	dict append confInfo ports-conf $ports
	return $confInfo
}

#解析配置信息的公共方法
proc parseTextInfo {root infoName} {
	set info [$root selectNodes $infoName/text()]
	set info [$info data]
	return $info
}

#获取配置设备OSPF协议的信息
#传入需要获取的设备编号
#返回一个字典，字典中protocol字段对应要配置的协议名称
#字典中commands字段对应一个由所有配置命令组成的链表
proc getProtocolInfo {id} {
	global root
	rootIsSet
	set equipments [$root selectNodes /config/equipments/equipment]
	set equipment [lindex $equipments $id]
	set conf [$equipment selectNodes config-info/conf]
	if {[catch {set protocol [parseTextInfo $conf protocol]} errMsg]} {
		puts "Equipment $id lacks config-info/conf/protocol tag"
		exit 1
	}
	dict append confInfo protocol $protocol
	set commandsNode [$conf selectNodes commands]
	set commands {}
	if {[catch {$commandsNode childNodes} errMsg]} {
		puts "Equipment $id lacks protocol commands"
		exit 1
	}
	foreach commandNode [$commandsNode childNodes] {
		set command [$commandNode selectNodes text()]
		set command [$command data]
		lappend commands $command
	}
	dict append confInfo commands $commands
	return $confInfo
}

#判断xml文件是否被载入
proc rootIsSet {} {
	global root
	if {$root == ""} {
		puts "Xml has not been initialed"
		exit 1
	}
}